package com.allwees.bs.module.oms.rest;

import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSON;
import com.allwees.bs.core.modelbase.constant.ResultCode;
import com.allwees.bs.core.modelbase.constant.ResultEnum;
import com.allwees.bs.core.modelbase.exception.BusinessException;
import com.allwees.bs.core.modelbase.vo.R;
import com.allwees.bs.module.lms.track.MileReprintParam;
import com.allwees.bs.module.lms.track.MileRequest;
import com.allwees.bs.module.lms.track.MileSubscribeParam;
import com.allwees.bs.module.lms.track.TrackingHelper;
import com.allwees.bs.module.lms.vo.MileSubscribeDetails;
import com.allwees.bs.module.oms.dao.OrderSkuSnapDao;
import com.allwees.bs.module.oms.entity.OmsOrder;
import com.allwees.bs.module.oms.entity.OmsOrderItem;
import com.allwees.bs.module.oms.entity.OrderSkuSnap;
import com.allwees.bs.module.oms.req.CodShippingReq;
import com.allwees.bs.module.oms.req.RetailerShippedReq;
import com.allwees.bs.module.oms.service.GeneralOmsOrderItemService;
import com.allwees.bs.module.oms.service.RetailerOmsOrderItemService;
import com.allwees.bs.module.oms.service.RetailerOmsOrderService;
import com.allwees.core.common.constant.EStatus;
import com.allwees.core.common.i18n.MessageSourceUtil;
import com.allwees.core.common.util.DateUtil;
import com.allwees.core.common.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 零售商 oms order api
 *
 * @author mouhaining
 * @since 2020-03-02 13:53
 */
@Slf4j
@RestController
@RequestMapping("/backstage/api/oms/oms_order/retailer")
public class RetailerOmsOrderApi extends BaseOmsOrderApi<RetailerOmsOrderService> {

    @Value("${allwees.imile.consignor}")
    private String consignor;

    @Value("${spring.profiles.active}")
    private String profile;

    @Value("${allwees.imile.customerId}")
    private String customerId;

    @Value("${allwees.imile.secretKey}")
    private String secretKey;

    @Autowired
    private RetailerOmsOrderItemService retailerOmsOrderItemService;

    @Autowired
    private GeneralOmsOrderItemService generalOmsOrderItemService;

    @Resource
    private OrderSkuSnapDao orderSkuSnapDao;

    /**
     * 下载Imile面单
     *
     * @param orderUuid
     * @param response
     */
    @GetMapping("/imileAwb")
    public void imileAwb(@RequestParam("orderUuid") String orderUuid, HttpServletResponse response) {
        MileRequest reprintOrder = MileRequest.newReprintRequest(new MileReprintParam(orderUuid), customerId, secretKey);
        long start = System.currentTimeMillis();
        MileSubscribeDetails details = TrackingHelper.subscribeMile(reprintOrder);
        log.info("===>imile pdf download consumes:{} ms", (System.currentTimeMillis() - start));
        if (details == null || !details.isSuccess()) {
            log.info("MileSubscribeDetails-reprintOrder:{}", JSON.toJSONString(details));
            throw BusinessException.getInstance(ResultCode.PARAM_ERROR, "打印COD面单错误~");

        }
        String imileAwb = details.getImileAwb();
        writePdf(orderUuid, Base64.decode(imileAwb), response);
    }

    /**
     * 创建COD物流并发货
     *
     * @param req
     * @return
     */
    @PostMapping("/codShip")
    public R codShip(@Validated @RequestBody CodShippingReq req) {
        String orderUuid = req.getOrderUuid();
        OmsOrder omsOrder = boService.findByUuid(orderUuid);
        if (omsOrder == null) {
            log.info("未查询到订单~");
            throw BusinessException.getInstance(ResultCode.NOT_FOUND, "未查询到订单~");
        }

        List<OmsOrderItem> orderItems = generalOmsOrderItemService
                .findByOrderUuid(orderUuid)
                .stream()
                .filter(item -> EStatus.OMS_WAIT_MERCHANT_SHIP.value().equals(item.getStatus()))
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(orderItems)) {
            log.info("未查询到代发货子单~");
            throw BusinessException.getInstance(ResultCode.NOT_FOUND, "未查询到代发货子单~");
        }
        MileSubscribeParam param = new MileSubscribeParam();
        String consigneeCountry = getConsigneeCountry();
        param.setConsigneeCountry(consigneeCountry);
        param.setConsignor(consignor);
        param.setTotalVolume(req.getVolumn());
        param.setTotalWeight(req.getWeight());
        //发货日期转成UTF+8
        ZonedDateTime ctt = Instant.now().atZone(ZoneId.of(ZoneId.SHORT_IDS.get("CTT")));
        param.setDispatchDate(ctt.format(DateTimeFormatter.ofPattern(DateUtil.SLASH_DATE_FORMAT)));
        param.setOrderCode(orderUuid);
        String firstName = StringUtil.trimToEmpty(omsOrder.getShippingAddressFirstName());
        String lastName = StringUtil.trimToEmpty(omsOrder.getShippingAddressLastName());
        param.setConsigneeContact(firstName + " " + lastName);
        param.setConsigneePhone(omsOrder.getShippingAddressPhone());
        param.setConsigneeCity(omsOrder.getShippingAddressCity());

        String address = StringUtil.trimToEmpty(omsOrder.getShippingAddressLine1()) + " " + StringUtil.trimToEmpty(omsOrder.getShippingAddressLine2());
        address = StringUtil.trimToEmpty(address).replace("#div#", ",");
        param.setConsigneeAddress(address);

        BigDecimal paymentAmount = orderItems.stream().map(OmsOrderItem::getAmt).reduce(BigDecimal::add).orElse(omsOrder.getAmt());
        if (BigDecimal.ZERO.compareTo(paymentAmount) == 0) {
            log.info("COD订单金额不能为0~");
            throw BusinessException.getInstance(ResultCode.PARAM_ERROR, "COD订单金额不能为0~");
        }
        param.setGoodsValue(paymentAmount.toPlainString());
        param.setCollectingMoney(paymentAmount.toPlainString());
        int sum = orderItems.stream().mapToInt(OmsOrderItem::getQuantity).sum();
        param.setSkuTotal(Integer.toString(sum));

        Set<String> orderItemUuids = orderItems.stream().map(OmsOrderItem::getUuid).collect(Collectors.toSet());
        List<OrderSkuSnap> skuSnaps = orderSkuSnapDao.findByOrderUuids(orderItemUuids);
        if (CollectionUtils.isEmpty(skuSnaps)) {
            log.info("未查询到OrderSkuSnap~");
            throw BusinessException.getInstance(ResultCode.PARAM_ERROR, "未查询到OrderSkuSnap~");
        }
        param.setSkuName(assembleSkuName(skuSnaps));
        MileRequest createOrder = MileRequest.newCreateRequest(param, customerId, secretKey);
        MileSubscribeDetails details = TrackingHelper.subscribeMile(createOrder);

        if (details == null) {
            log.info("生成COD订单错误");
            throw BusinessException.getInstance(ResultCode.PARAM_ERROR, "生成COD订单错误~");
        }

        String expressNo = details.getExpressNo();
        if (!details.isSuccess() && StringUtil.isBlank(expressNo)) {
            log.info("MileSubscribeDetails-createOrder:{}", JSON.toJSONString(details));
            throw BusinessException.getInstance(ResultCode.PARAM_ERROR, details.getDescription());
        }

        //接已有的发货逻辑
        RetailerShippedReq shippedReq = new RetailerShippedReq();
        shippedReq.setExpressCode(expressNo);
        shippedReq.setLogisticsUuid(req.getLogisticsUuid());
        shippedReq.setOrderItemUuids(orderItems.stream().map(OmsOrderItem::getUuid).collect(Collectors.toSet()));
        retailerOmsOrderItemService.doShipped(shippedReq);

//        String imileAwb = details.getImileAwb();
//        //重复提交时，没有面单
//        if(StringUtil.isNotBlank(imileAwb)){
//            writePdf(orderUuid,Base64.decode(imileAwb),response);
//            return null;
//        }
        return R.ok("发货成功,请到'已发货'页面下载面单~");
    }

    /**
     * 清关要求：productName1*num1,productName2*num2,...
     * 最大长度300
     *
     * @param skuSnaps
     * @return
     */
    private String assembleSkuName(List<OrderSkuSnap> skuSnaps) {
        Map<String, Integer> nameVsNum =
                skuSnaps.stream().collect(Collectors.groupingBy(e -> StringUtil.trimToEmpty(e.getProductName()), Collectors.summingInt(OrderSkuSnap::getQuantity)));
        List<String> nameList = new ArrayList<>(nameVsNum.size());
        for (Map.Entry<String, Integer> entry : nameVsNum.entrySet()) {
            nameList.add(entry.getKey() + "*" + entry.getValue() + ";\n");
        }

        StringBuilder sb = new StringBuilder();

        for (String name : nameList) {
            if (sb.length() + name.length() >= 300) {
                break;
            }
            sb.append(name);
        }
        String skuName = StringUtil.trim(sb.toString());
        log.info("===>imile skuName:\n{}", skuName);
        return skuName;
    }

    private String getConsigneeCountry() {
        if ("ae".equals(profile) || "aen".equals(profile)) {
            return "UAE";
        }

        if ("sa".equals(profile) || "san".equals(profile)) {
            return "KSA";
        }

        if ("test".equals(profile)) {
            return "KSA";
        }

        throw BusinessException.getInstance(ResultEnum.NOT_FOUND.getCode(), MessageSourceUtil.getMessage(Locale.US, ResultEnum.NOT_FOUND));
    }

    /**
     * 浏览器下载PDF面单
     *
     * @param response
     * @param fileName
     * @param content
     */
    private void writePdf(String fileName, byte[] content, HttpServletResponse response) {
        try {
            String encoding = StandardCharsets.UTF_8.name();
            response.setCharacterEncoding(encoding);
            fileName = URLEncoder.encode(fileName, encoding);
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".pdf");
            response.setContentType(MediaType.APPLICATION_PDF_VALUE);
            response.getOutputStream().write(content);
        } catch (IOException e) {
            log.error("write pdf error:{}", e.getMessage(), e);
        }
    }
}
